package org.jvm.rtda.heap;

import org.jvm.classfile.constantinfo.*;
import org.jvm.rtda.heap.symref.*;

/**
 * 运行时常量池
 * 存储.class文件中的字面量和符号引用
 *
 * @author 王思翔
 * @date 2023/2/4
 */
public class ConstantPool {

    /**
     * 常量池所在类
     */
    private Klass klass;

    private Object[] consts;


    public ConstantPool(Klass klass, org.jvm.classfile.ConstantPool constantPool) {
        this.klass = klass;
        ConstantInfo[] constantInfos = constantPool.getConstantInfos();
        this.consts = new Object[constantInfos.length];
        //常量池索引0号位为无效位
        for (int i = 1; i < constantInfos.length; i++) {
            if (constantInfos[i] instanceof ConstantIntegerInfo) {
                this.consts[i] = ((ConstantIntegerInfo) constantInfos[i]).getVal();
            } else if (constantInfos[i] instanceof ConstantFloatInfo) {
                this.consts[i] = ((ConstantFloatInfo) constantInfos[i]).getVal();
            } else if (constantInfos[i] instanceof ConstantLongInfo) {
                this.consts[i] = ((ConstantLongInfo) constantInfos[i]).getVal();
                i++;
            } else if (constantInfos[i] instanceof ConstantDoubleInfo) {
                this.consts[i] = ((ConstantDoubleInfo) constantInfos[i]).getVal();
                i++;
            } else if (constantInfos[i] instanceof ConstantStringInfo) {
                this.consts[i] = ((ConstantStringInfo) constantInfos[i]).string();
            }
            //下面的步骤先初始化符号引用，将被引用类的全类名进行注入，之后会进行引用符号的解析
            //类符号引用
            else if (constantInfos[i] instanceof ConstantClassInfo) {
                this.consts[i] = newClassRef(this, (ConstantClassInfo) constantInfos[i]);
            }
            //字段符号引用
            else if (constantInfos[i] instanceof ConstantFieldrefInfo) {
                this.consts[i] = newFieldRef(this, (ConstantFieldrefInfo) constantInfos[i]);
            }
            //方法符号引用
            else if (constantInfos[i] instanceof ConstantMethodrefInfo) {
                this.consts[i] = newMethodRef(this, (ConstantMethodrefInfo) constantInfos[i]);
            }
            //接口符号引用
            else if (constantInfos[i] instanceof ConstantInterfaceMethodrefInfo) {
                this.consts[i] = newInterfaceMethodRef(this, (ConstantInterfaceMethodrefInfo) constantInfos[i]);
            }
        }
    }

    private Object newInterfaceMethodRef(ConstantPool constantPool, ConstantInterfaceMethodrefInfo constantInfo) {
        return new InterfaceMethodRef(constantPool, constantInfo.className(), constantInfo.nameAndDescriptor().getName(),
                constantInfo.nameAndDescriptor().getDescriptor());
    }

    private Object newMethodRef(ConstantPool constantPool, ConstantMethodrefInfo constantInfo) {
        return new MethodRef(constantPool, constantInfo.className(), constantInfo.nameAndDescriptor().getName(),
                constantInfo.nameAndDescriptor().getDescriptor());
    }

    private Object newFieldRef(ConstantPool constantPool, ConstantFieldrefInfo constantInfo) {
        return new FieldRef(constantPool, constantInfo.className(), constantInfo.nameAndDescriptor().getName(),
                constantInfo.nameAndDescriptor().getDescriptor());
    }

    private Object newClassRef(ConstantPool constantPool, ConstantClassInfo constantInfo) {
        return new ClassRef(constantPool, constantInfo.name());
    }

    public Object getConstant(int index) {
        return this.consts[index];
    }

    public Klass getKlass() {
        return klass;
    }

}
